package syncWaitGroup

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

/** sync.WaitGroup 是 Go 语言中用于等待一组 goroutine 执行完成的同步工具。它通过计数器来实现等待机制。

基本结构和方法：
	var wg sync.WaitGroup
	// 主要方法：
	wg.Add(n) // 增加计数器值
	wg.Done() // 减少计数器值（相当于 Add(-1)）
	wg.Wait() // 阻塞直到计数器为0
*/

func Test() {

	// 示例1
	//case1()

	// 示例2 并发下载文件
	//case2()

	// 示例3 根据输入的数字，是偶数返回数字薪资，否则返回处理消息
	case3()
}

// 示例1
func case1() {

	var wg sync.WaitGroup

	for i := 1; i <= 3; i++ {
		wg.Add(1) //计数器增加
		go worker1(i, &wg)
	}
	wg.Wait() //等待所有的go协程执行结束
	fmt.Println("case1() 执行完毕...")

}

func worker1(i int, wg *sync.WaitGroup) {
	defer wg.Done() //计数器减一，同时使用了延迟关键字
	fmt.Printf("接收参数 worker1(%d)  \n", i)
	time.Sleep(time.Second)
	fmt.Printf("worker1(%d) end...  \n", i)
}

// 示例2 并发下载文件
func case2() {
	var wg sync.WaitGroup
	files := []string{"file_one.txt", "file_two.txt", "file_three.txt", "file_four.txt", "file_five.txt"}

	fmt.Println("开始并发下载...")
	for _, file := range files {
		wg.Add(1)
		go download1(file, &wg)
	}

	wg.Wait() //阻塞
	fmt.Println("case2() 执行完毕 ...")

}

func download1(fileName string, wg *sync.WaitGroup) {
	defer wg.Done()
	fmt.Printf("开始下载：%s  \n", fileName)
	time.Sleep(2 * time.Second) // 模拟下载时间
	fmt.Printf("下载完成：%s  \n", fileName)
}

// 示例3 根据输入的数字，是偶数返回数字薪资，否则返回处理消息
func case3() {
	var wg sync.WaitGroup
	sucRes := make(chan string, 5)  //定义能处理偶数的信道
	failRes := make(chan string, 5) //定义不能处理偶数的信道

	for i := 1; i <= 5; i++ {
		// 定义随机数 100以内
		randNum := rand.Intn(100)
		wg.Add(1)
		go eventCalcultor(randNum, &wg, sucRes, failRes)
	}

	// 等待所偶协程结束
	go func() {
		wg.Wait()
		close(sucRes)
		close(failRes)
	}()

	// 处理sucRes
	for res := range sucRes {
		fmt.Println(res)
	}

	// 处理failRes
	for res := range failRes {
		fmt.Println(res)
	}

	fmt.Println("case3() end ...")
}

func eventCalcultor(num int, wg *sync.WaitGroup, sucRes chan<- string, failRes chan<- string) {
	defer wg.Done()

	if num%2 == 0 {
		time.Sleep(time.Second) //睡眠一下
		// 是偶数
		sucRes <- fmt.Sprint("读取到的偶数是 %d", num)
	} else {
		failRes <- fmt.Sprint("读取到不是偶数，而是奇数 %d", num)
	}
}
